Un graphe est un ensemble de sommets reliés par des arêtes. Les graphes sont utilisés pour modéliser des relations entre des objets, comme les réseaux sociaux, les réseaux de transport, les réseaux de communication, etc. Les graphes peuvent être orientés ou non orientés, selon que les arêtes ont une direction ou non. Les graphes peuvent également être pondérés, c'est-à-dire que les arêtes ont un poids ou une valeur associée.
Dans ce TP, vous allez manipuler un graphe représentant les relations entre super-héros et super-vilains. Vous implémenterez des algorithmes classiques (parcours en largeur, Dijkstra, centralité) pour répondre à des questions stratégiques.
Voici la liste des personnages et leurs relations (poids = force de la relation) :
| Personnage 1 | Personnage 2 | Poids | Type |
|---|---|---|---|
| Spider-Man | Iron Man | 3 | Allié proche |
| Spider-Man | Doctor Strange | 1 | Connaissance |
| Spider-Man | Black Panther | 2 | Allié occasionnel |
| Iron Man | Captain America | 4 | Équipe |
| Iron Man | Black Widow | 3 | Allié proche |
| Iron Man | Ant-Man | 2 | Allié occasionnel |
| Captain America | Black Widow | 4 | Équipe |
| Captain America | Hawkeye | 4 | Équipe |
| Captain America | Hulk | 3 | Allié proche |
| Black Widow | Hawkeye | 3 | Allié proche |
| Black Widow | Scarlet Witch | 2 | Allié occasionnel |
| Thor | Loki | 5 | Ennemi |
| Thor | Hulk | 2 | Connaissance |
| Thor | Doctor Strange | 1 | Connaissance |
| Loki | Thanos | 3 | Allié proche |
| Thanos | Vision | 5 | Ennemi |
| Thanos | Scarlet Witch | 5 | Ennemi |
| Doctor Strange | Scarlet Witch | 3 | Allié proche |
| Doctor Strange | Vision | 2 | Allié occasionnel |
| Black Panther | Hulk | 1 | Connaissance |
| Black Panther | Star-Lord | 2 | Allié occasionnel |
| Hulk | Ant-Man | 1 | Connaissance |
| Ant-Man | Hawkeye | 2 | Allié occasionnel |
| Hawkeye | Star-Lord | 1 | Connaissance |
| Vision | Scarlet Witch | 4 | Équipe |
Consigne : Construisez le graphe sous forme de dictionnaire Python (clé = sommet, valeur = liste/dictionnaire des voisins et poids).
graphe_non_pondere = {
"Spider-Man": ["Iron Man", "Doctor Strange", "Black Panther"],
"Iron Man": ["Spider-Man", "Captain America", "Black Widow", "Ant-Man"],
"Captain America": ["Iron Man", "Black Widow", "Hawkeye", "Hulk"],
"Black Widow": ["Iron Man", "Captain America", "Hawkeye", "Scarlet Witch"],
"Thor": ["Loki", "Hulk", "Doctor Strange"],
"Loki": ["Thor", "Thanos"],
"Thanos": ["Loki", "Vision", "Scarlet Witch"],
"Doctor Strange": ["Spider-Man", "Thor", "Scarlet Witch", "Vision"],
"Black Panther": ["Spider-Man", "Hulk", "Star-Lord"],
"Hulk": ["Captain America", "Thor", "Black Panther", "Ant-Man"],
"Ant-Man": ["Iron Man", "Hulk", "Hawkeye"],
"Hawkeye": ["Captain America", "Black Widow", "Ant-Man", "Star-Lord"],
..........
}
graphe_pondere = {
"Spider-Man": {"Iron Man": 3, "Doctor Strange": 1, "Black Panther": 2},
"Iron Man": {"Spider-Man": 3, "Captain America": 4, "Black Widow": 3, "Ant-Man": 2},
"Captain America": {"Iron Man": 4, "Black Widow": 4, "Hawkeye": 4, "Hulk": 3},
"Black Widow": {"Iron Man": 3, "Captain America": 4, "Hawkeye": 3, "Scarlet Witch": 2},
"Thor": {"Loki": 5, "Hulk": 2, "Doctor Strange": 1},
"Loki": {"Thor": 5, "Thanos": 3},
"Thanos": {"Loki": 3, "Vision": 5, "Scarlet Witch": 5},
"Doctor Strange": {"Spider-Man": 1, "Thor": 1, "Scarlet Witch": 3, "Vision": 2},
"Black Panther": {"Spider-Man": 2, "Hulk": 1, "Star-Lord": 2},
"Hulk": {"Captain America": 3, "Thor": 2, "Black Panther": 1, "Ant-Man": 1},
"Ant-Man": {"Iron Man": 2, "Hulk": 1, "Hawkeye": 2},
"Hawkeye": {"Captain America": 4, "Black Widow": 3, "Ant-Man": 2, "Star-Lord": 1},
..........
}
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
for sommet in graphe_pondere:
G.add_node(sommet)
for sommet, voisins in graphe_pondere.items():
for voisin, poids in voisins.items():
G.add_edge(sommet, voisin, weight=poids)
couleurs_aretes = []
for u, v, data in G.edges(data=True):
poids = data['weight']
if poids == 1:
couleurs_aretes.append('gray') # Connaissance
elif poids == 2:
couleurs_aretes.append('lightblue') # Alliés occasionnels
elif poids == 3:
couleurs_aretes.append('green') # Alliés proches
elif poids == 4:
couleurs_aretes.append('blue') # Équipe
elif poids == 5:
couleurs_aretes.append('red') # Ennemis
pos = nx.spring_layout(G, seed=42) # Positionnement des sommets
nx.draw(G, pos, with_labels=True, node_size=2000, node_color="lightblue", font_size=10, font_weight="bold", edge_color=couleurs_aretes, width=2)
etiquettes_aretes = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels=etiquettes_aretes)
plt.text(0.02, 0.95, "Légende :", transform=plt.gca().transAxes, fontsize=10, verticalalignment='top')
plt.text(0.02, 0.90, "Gris : Connaissance (poids 1)", transform=plt.gca().transAxes, fontsize=10, verticalalignment='top', color='gray')
plt.text(0.02, 0.85, "Bleu clair : Alliés occasionnels (poids 2)", transform=plt.gca().transAxes, fontsize=10, verticalalignment='top', color='lightblue')
plt.text(0.02, 0.80, "Vert : Alliés proches (poids 3)", transform=plt.gca().transAxes, fontsize=10, verticalalignment='top', color='green')
plt.text(0.02, 0.75, "Bleu : Équipe (poids 4)", transform=plt.gca().transAxes, fontsize=10, verticalalignment='top', color='blue')
plt.text(0.02, 0.70, "Rouge : Ennemis (poids 5)", transform=plt.gca().transAxes, fontsize=10, verticalalignment='top', color='red')
plt.title("Réseau social des super-héros (graphe pondéré)")
plt.show()
Implémentez l'algorithme de parcours en largeur
from collections import deque
def parcours_en_largeur(graphe, depart, arrivee):
parent = {depart: None}
file_attente = deque([depart])
print(file_attente)
while file_attente:
sommet_courant = file_attente.popleft()
if sommet_courant == arrivee:
chemin = []
while sommet_courant is not None:
chemin.append(sommet_courant)
sommet_courant = parent[sommet_courant]
return chemin[::-1]
for voisin in graphe[sommet_courant]:
if voisin not in parent:
parent[voisin] = sommet_courant
file_attente.append(voisin)
return None
Implémentez l'algorithme de parcours en profondeur pour parcourir le graphe .
def parcours_profondeur(graphe, sommet_depart, visites=None, chemin=None):
if visites is None:
visites = set()
if chemin is None:
chemin = []
visites.add(sommet_depart)
chemin.append(sommet_depart)
for voisin in graphe[sommet_depart]:
if voisin not in visites:
parcours_profondeur(graphe, voisin, visites, chemin)
return chemin
def afficher_parcours_profondeur(graphe, sommet_depart):
chemin = parcours_profondeur(graphe, sommet_depart)
print(f"Parcours en profondeur depuis {sommet_depart} : {chemin}")
return chemin
Implémentez l'algorithme de Dijkstra
import heapq
def dijkstra(graphe, depart, arrivee):
distances = {sommet: float('inf') for sommet in graphe}
distances[depart] = 0
parent = {depart: None}
tas_priorite = [(0, depart)]
while tas_priorite:
distance_courante, sommet_courant = heapq.heappop(tas_priorite)
if distance_courante > distances[sommet_courant]:
continue
for voisin, poids in graphe[sommet_courant].items():
distance = distance_courante + poids
if distance < distances[voisin]:
distances[voisin] = distance
parent[voisin] = sommet_courant
heapq.heappush(tas_priorite, (distance, voisin))
chemin = []
sommet = arrivee
while sommet is not None:
chemin.append(sommet)
sommet = parent.get(sommet, None)
return chemin[::-1] # Retourne le chemin dans le bon sens